package ai1;

import agents.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author orcas
 *  bla  bla
 */
public class Enviroment {

    public char[][] map;
    public int rows,  cols;
    public Vector<Agent> agents;

    private int transform(int row, int col) {
        return (row * cols) + col + 1;
    }

    public Enviroment(String filename) {
        BufferedReader in = null;
        try {
            in = new BufferedReader(new FileReader(filename));
            Vector<String> v = new Vector<String>();
            while (in.ready()) {
                v.add(in.readLine());
            }
            rows = v.size();
            map = new char[rows][];
            for (int i = 0; i < rows; i++) {
                map[i] = v.get(i).toCharArray();
            }
            cols = v.get(0).length();
            sendMessage("Board " + cols + " " + rows);

            String walls = "";
            String flags = "";
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    if (map[i][j] == 'F') {
                        flags += " " + transform(i, j);
                    } else if (map[i][j] == '#') {
                        walls += " " + transform(i, j);
                    //TODO: ice
                    }
                }
            }
            if (walls.length() > 0) {
                sendMessage("Walls" + walls);
            }
            if (flags.length() > 0) {
                sendMessage("Flags" + flags);
            }
            agents = new Vector<Agent>();

        } catch (IOException ex) {
            Logger.getLogger(Enviroment.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(Enviroment.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * "Agent <agent name> <color> <orientation> <cell>" - initialize agent in 	the grid:
    
    <agent name> - assign a name to each agent
    <color> - can be "Red" or "Blue"  (case sensitive)
    <orientation> - can be "North" / "South" / "East" "West"
    <cell> = grid location
    
    for example:
    
    "Agent dan Red East 13" - creates a red agent named dan which turn to 		east in cell 13.
     * @param agent
     */
    private void addAgent(Agent agent, String color) {
        sendMessage("Agent " + agent.getName() + " " + color + " " + agent.getOrientation() + " " + transform(agent.getRow(), agent.getCol()));
        agents.add(agent);
        map[agent.getRow()][agent.getCol()] = 'A';
    }

    /**
     * sanity check
     * @param newCell
     * @return
     */
    public boolean isCellFree(int row, int col) {
        boolean ans= row >= 0 && row < rows &&
                col >= 0 && col < cols &&
                (map[row][col] == ' ' || map[row][col] == 'F' || map[row][col] == '.');
        if(!ans)
            System.out.println("cell "+row+","+col+" is NOT free! it has a '"+map[row][col]+"'");
        return ans;
    }
    public boolean isCellFree(int[] newCell) {
        return newCell!=null && newCell.length == 2 && isCellFree(newCell[0], newCell[1]);
    }

    public void run() {
        while (true) {
            for (Agent a : agents) {
                String move = a.getMove(this);
                if (move != null) {
                    //check if it's a legal move:
                    if (move.equals("LEFT") || move.equals("RIGHT") ||
                            (move.equals("FWD") && isCellFree(a.getForward()))) {
                        sendMessage("MoveAgent " + a.getName() + " " + move);
                        if(move.equals("FWD")) {
                            map[a.getRow()][a.getCol()]=' ';
                            int[] newCell=a.getForward();
                            map[newCell[0]][newCell[1]]='A';
                        }
                        a.updatePosition(move);
                    } else {
                        Logger.getLogger(Enviroment.class.getName()).log(Level.SEVERE, "Illegal move attempted!");
                    }
                }
            }
        }
    }

    /**
     * This procedure send a message to server
     * 
     * @param msg
     * @throws IOException
     */
    private void sendMessage(String msg) {
        try {
            System.out.println("sending msg '" + msg + "'");
            DatagramSocket clientSocket = new DatagramSocket();

            InetAddress IPAddress = InetAddress.getByName("127.0.0.1");

            byte[] sendData = new byte[1024];
            byte[] receiveData = new byte[1024];
            sendData = msg.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 9876);

            clientSocket.send(sendPacket);

            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

            clientSocket.receive(receivePacket);

            String modifiedSentence = new String(receivePacket.getData());

            System.out.println("FROM SERVER: " + modifiedSentence.trim());
            clientSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(Enviroment.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        Enviroment env = new Enviroment("map.txt");

        System.out.println("add another agent: 1. human, 2.dumb automaton, 3. dumb greedy, any other key: done.");
        //TODO get input
        env.addAgent(new HumanAgent(("benny"), 5, 3, "North"), "Blue");
        env.addAgent(new GreedyAgent(("Bellman"), 3, 11, "North"), "Red");
        env.addAgent(new GreedyAgent(("Ford"), 6, 16, "West"), "Red");
        env.addAgent(new AutomatonAgent(("Patrol"), 2, 14, "West"), "Red");
        env.run();
    }
}
